home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / Xconq 7.0d16 / Xconq 7.0d16 src / mac / macmap2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-16  |  25.2 KB  |  1,090 lines  |  [TEXT/KAHL]

  1. /* Copyright (c) 1992, 1993  Stanley T. Shebs. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. /* Map interaction for the Mac interface to Xconq. */
  6.  
  7. #include "conq.h"
  8. #include "mac.h"
  9.  
  10. /* This is a temporary used by procs. */
  11.  
  12. Map *curmap = NULL;
  13.  
  14. /* This scroll proc is shared by both the horizontal and vertical scrollbars. */
  15.  
  16. pascal void
  17. map_scroll_proc(control, code)
  18. ControlHandle control;
  19. short code;
  20. {
  21.     int curvalue, pagesize, jump;
  22.  
  23.     if (curmap == NULL) return;
  24.     /* The page jump should be most but not all of a screenful. */
  25.     if (control == curmap->hscrollbar) {
  26.         pagesize = (2 * curmap->pxw) / 3;
  27.     } else {
  28.         pagesize = (2 * curmap->pxh) / 3;
  29.     }
  30.     switch (code) {
  31.         case inPageDown:
  32.             jump = pagesize;
  33.             break;
  34.         case inDownButton:
  35.             jump = 4;
  36.             break;
  37.         case inPageUp:
  38.             jump = 0 - pagesize;
  39.             break;
  40.         case inUpButton:
  41.             jump = -4;
  42.             break;
  43.         default:
  44.             jump = 0;
  45.             break;
  46.     }
  47.     /* Letting control's code do the max/min hacking. */
  48.     SetCtlValue(control, GetCtlValue(control) + jump);
  49.     curvalue = GetCtlValue(control);
  50.     /* Tweak the map's own variables to match. */
  51.     if (control == curmap->hscrollbar) {
  52.         curmap->sx = curvalue;
  53.     } else {
  54.         curmap->sy = curvalue;
  55.     }
  56.     curmap = NULL;
  57. }
  58.  
  59. /* Handle a mouse down in the map window. */
  60.  
  61. do_mouse_down_map(map, mouse, mods)
  62. Map *map;
  63. Point mouse;
  64. int mods;
  65. {
  66.     ControlHandle control;
  67.     short part, value;
  68.     long oldsx, oldsy;
  69.     WindowPtr window = map->window;
  70.  
  71.     part = FindControl(mouse, window, &control);
  72.     if (control == map->hscrollbar) {
  73.         /* Handle the horizontal scrollbar. */
  74.         oldsx = map->sx;
  75.         part = FindControl(mouse, window, &control);
  76.         switch (part) {
  77.             case inThumb:
  78.                 /* (should add tracking ability) */
  79.                 part = TrackControl(control, mouse, NULL);
  80.                 map->sx = GetCtlValue(control);
  81.                 break;
  82.             default:
  83.                 curmap = map;
  84.                 part = TrackControl(control, mouse, (ProcPtr) map_scroll_proc);
  85.                 break;
  86.         }
  87.         if (oldsx != map->sx) {
  88.             focus_on_center(map);
  89.             force_map_update(map);
  90.             draw_related_maps(map);
  91.         }
  92.     } else if (control == map->vscrollbar) {
  93.         /* Handle the vertical scrollbar. */
  94.         oldsy = map->sy;
  95.         part = FindControl(mouse, window, &control);
  96.         switch (part) {
  97.             case inThumb:
  98.                 part = TrackControl(control, mouse, NULL);
  99.                 map->sy = GetCtlValue(control);
  100.                 break;
  101.             default:
  102.                 curmap = map;
  103.                 part = TrackControl(control, mouse, (ProcPtr) map_scroll_proc);
  104.                 break;
  105.         }
  106.         if (oldsy != map->sy) {
  107.             focus_on_center(map);
  108.             force_map_update(map);
  109.             draw_related_maps(map);
  110.         }
  111.     } else if (mouse.h <= conwid) {
  112.         /* Interpret as a control panel hit. */
  113.         do_mouse_down_map_control_panel(map, mouse.h, mouse.v, mods);
  114.     } else {
  115.         do_mouse_down_map_content(map, mouse.h, mouse.v, mods);
  116.     }
  117. }
  118.  
  119. do_mouse_down_map_control_panel(map, h, v, mods)
  120. Map *map;
  121. int h, v, mods;
  122. {
  123.     int i, winh = map->window->portRect.bottom - map->window->portRect.top;
  124.     Unit *unit;
  125.  
  126.     /* (should better organize tests here) */
  127.     if (between(winh - 2 * sbarwid, v, winh)) {
  128.         switch ((winh - v) / sbarwid) {
  129.             case 0:
  130.                 magnify_map(map, ((h < conwid / 2) ? -1 : 1));
  131.                 break;
  132.             case 1:
  133.                 modaltool = 1;
  134.                 break;
  135.         }
  136.     } else if (v < 32) {
  137.         toggle_survey(map);
  138.     } else if ((v - 32) < 5 * 15) {
  139.         switch ((v - 32) / 15) {
  140.             case 0:
  141.                 if (h < conwid / 2) {
  142.                     select_previous_awake_mover(map);
  143.                 } else {
  144.                     select_next_awake_mover(map);
  145.                 }
  146.                 break;
  147.             case 1:
  148.                 if (h < conwid / 2) {
  149.                     select_previous_mover(map);
  150.                 } else {
  151.                     select_next_mover(map);
  152.                 }
  153.                 break;
  154.             case 2:
  155.                 if (h < conwid / 2) {
  156.                     select_previous_actor(map);
  157.                 } else {
  158.                     select_next_actor(map);
  159.                 }
  160.                 break;
  161.             case 3:
  162.                 if (h < conwid / 2) {
  163.                     select_previous_unit(map);
  164.                 } else {
  165.                     select_next_unit(map);
  166.                 }
  167.                 break;
  168.             case 4:
  169.                 SysBeep(20);
  170.                 break;
  171.         }
  172.     } else if (v - 32 - 5*15 - 2 - 5/*why?*/ < 5 * 11) {
  173.         switch ((v - 32 - 5*15 - 2 - 5/*why?*/) / 11) {
  174.             case 0:
  175.                 toggle_map_grid(map);
  176.                 break;
  177.             case 1:
  178.                 toggle_map_names(map);
  179.                 break;
  180.             case 2:
  181.                 if (people_sides_defined()) {
  182.                     toggle_map_people(map);
  183.                 }
  184.                 break;
  185.             case 3:
  186.                 toggle_map_plans(map);
  187.                 break;
  188.             case 4:
  189.                 toggle_map_ai(map);
  190.                 break;
  191.         }
  192.     } else if (mayseeall) {
  193.         weseeall = !weseeall;
  194.         force_map_update(map);
  195.     }
  196. }
  197.  
  198. toggle_survey(map)
  199. Map *map;
  200. {
  201.     int i;
  202.     Unit *unit;
  203.  
  204.     map->moveonclick = !map->moveonclick;
  205.     map->autoselect = !map->autoselect;
  206.     draw_control_panel(map);
  207.     if (map->autoselect) {
  208.         if (map->numselections > 0) {
  209.             for (i = 0; i < map->numselections; ++i) {
  210.                 if ((unit = map->selections[i]) != NULL) {
  211.                     map->curunit = autonext_unit(dside, unit);
  212.                     select_exactly_one_unit(map, map->curunit);
  213.                 }
  214.             }
  215.         }
  216.     }
  217. }
  218.  
  219. magnify_map(map, inout)
  220. Map *map;
  221. int inout;
  222. {
  223.     set_map_mag(map, map->power + inout);
  224. }
  225.  
  226. /* This sets the map's magnification directly and updates it. */
  227.  
  228. set_map_mag(map, newpower)
  229. Map *map;
  230. int newpower;
  231. {
  232.     newpower = clip_to_limits(0, newpower, NUMPOWERS-1);
  233.     if (map->power != newpower) {
  234.         set_map_power(map, newpower);
  235.         center_on_focus(map);
  236.         /* Doubling these calcs is really crude... */
  237.         set_map_scrollbars(map);
  238.         set_map_viewport(map);
  239.         set_map_scrollbars(map);
  240.         set_map_viewport(map);
  241.         force_map_update(map);
  242.         draw_related_maps(map);
  243.     }
  244. }
  245.  
  246. toggle_map_grid(map)
  247. Map *map;
  248. {
  249.     map->drawgrid = !map->drawgrid;
  250.     /* (should not do a total redraw?) */
  251.     force_map_update(map);
  252. }
  253.  
  254. toggle_map_topline(map)
  255. Map *map;
  256. {
  257.     Rect tmprect;
  258.     GrafPtr oldport;
  259.     RgnHandle tmprgn;
  260.  
  261.     map->toph = (map->toph ? 0 : tophgt);
  262.     set_content_rect(map);
  263.     if (map->toph) {
  264.          GetPort(&oldport);
  265.         SetPort(map->window);
  266. #if 0
  267.         tmprect = map->window->portRect;
  268.         tmprect.left += conwid;
  269.         tmprect.right -= sbarwid;  tmprect.bottom -= sbarwid;
  270. /*        ScrollRect(&tmprect, 0, map->toph, tmprgn); */
  271.         /* (should draw the topline here now) */
  272. #endif
  273.         SetPort(oldport);
  274.         force_map_update(map);
  275.     } else {
  276.         force_map_update(map);
  277.     }
  278. }
  279.  
  280. toggle_map_other_maps(map)
  281. Map *map;
  282. {
  283.     map->drawothermaps = !map->drawothermaps;
  284.     /* (should not do a total redraw) */
  285.     force_map_update(map);
  286. }
  287.  
  288. toggle_map_lighting(map)
  289. Map *map;
  290. {
  291.     map->drawlighting = !map->drawlighting;
  292.     /* We have to do a total redraw. */
  293.     force_map_update(map);
  294. }
  295.  
  296. toggle_map_names(map)
  297. Map *map;
  298. {
  299.     map->drawnames = !map->drawnames;
  300.     /* (if now on, should draw names on top of everything, don't redraw everything) */
  301.     if (map->hh > 5) {
  302.         force_map_update(map);
  303.     } else {
  304.         /* (should be a force update on control panel alone) */
  305.         draw_control_panel(map);
  306.     }
  307. }
  308.  
  309. toggle_map_people(map)
  310. Map *map;
  311. {
  312.     map->drawpeople = !map->drawpeople;
  313.     if (bwid2[map->power] > 0) {
  314.         force_map_update(map);
  315.     } else {
  316.         /* (should be a force update on control panel alone) */
  317.         draw_control_panel(map);
  318.     }
  319. }
  320.  
  321. toggle_map_elevations(map)
  322. Map *map;
  323. {
  324.     map->drawelevations = !map->drawelevations;
  325.     force_map_update(map);
  326. }
  327.  
  328. toggle_map_materials(map, m)
  329. Map *map;
  330. int m;
  331. {
  332.     map->drawmaterials[m] = !map->drawmaterials[m];
  333.     map->nummaterialstodraw += (map->drawmaterials[m] ? 1 : -1);
  334.     force_map_update(map);
  335. }
  336.  
  337. toggle_map_temperature(map, m)
  338. Map *map;
  339. int m;
  340. {
  341.     map->drawtemperature = !map->drawtemperature;
  342.     force_map_update(map);
  343. }
  344.  
  345. toggle_map_winds(map, m)
  346. Map *map;
  347. int m;
  348. {
  349.     map->drawwinds = !map->drawwinds;
  350.     force_map_update(map);
  351. }
  352.  
  353. toggle_map_clouds(map, m)
  354. Map *map;
  355. int m;
  356. {
  357.     map->drawclouds = !map->drawclouds;
  358.     force_map_update(map);
  359. }
  360.  
  361. toggle_map_storms(map, m)
  362. Map *map;
  363. int m;
  364. {
  365.     map->drawstorms = !map->drawstorms;
  366.     force_map_update(map);
  367. }
  368.  
  369. toggle_map_plans(map)
  370. Map *map;
  371. {
  372.     map->drawplans = !map->drawplans;
  373.     if (map->numselections > 0) {
  374.         force_map_update(map);
  375.     } else {
  376.         /* (should be a force update on control panel alone) */
  377.         draw_control_panel(map);
  378.     }
  379. }
  380.  
  381. toggle_map_ai(map)
  382. Map *map;
  383. {
  384.     if (!side_has_ai(dside)) return;
  385.     map->drawai = !map->drawai;
  386.     force_map_update(map);
  387. }
  388.  
  389. static int selrect;
  390. static int downx, downy, downdir;
  391.  
  392. do_mouse_down_map_content(map, h, v, mods)
  393. Map *map;
  394. int h, v, mods;
  395. {
  396.     int i;
  397.     Unit *unit;
  398.     
  399.     /* Remember this hex. */
  400.     nearest_cell(map, h, v, &downx, &downy);
  401.     /* Assume that last place clicked is a reasonable focus. */
  402.     if (inside_area(downx, downy)) {
  403.         map->vcx = downx;  map->vcy = downy;
  404.     }
  405.     if (modaltool > 0) {
  406.         switch (modaltool) {
  407.             case 1:
  408.                 select_area_and_zoom(map, h, v, mods);
  409.                 break;
  410.             case 2:
  411.                 if (do_fire_command()) {
  412.                     modaltool = 0;
  413.                 }
  414.                 break;
  415.             default:
  416.                 /* (should error out) */
  417.                 break;
  418.         }
  419.     } else if (mods & cmdKey) {
  420.         if (map->moveonclick && map->autoselect) {
  421.             unselect_all(map);
  422.             nearest_unit(map, h, v, &unit);
  423.             if (unit != NULL && side_controls_unit(dside, unit)) {
  424.                 /* The nearest unit will become the "current unit". */
  425.                 map->curunit = unit;
  426.                 select_unit_on_map(map, unit);
  427.                 draw_selections(map);
  428.                 move_on_drag(map, unit, mods);
  429.             } else {
  430.                 select_all_dragged_over(map, h, v, mods);
  431.                 /* Pick the first of the multiple selection as the "current unit". */
  432.                 if (map->numselections > 0) {
  433.                     map->curunit = map->selections[0];
  434.                 }
  435.             }
  436.         } else {
  437.             for (i = 0; i < map->numselections; ++i) {
  438.                 if ((unit = map->selections[i]) != NULL) {
  439.                     move_the_selected_unit(map, unit, h, v);
  440.                 }
  441.             }
  442.         }
  443.     } else if (mods & optionKey) {
  444.         for (i = 0; i < map->numselections; ++i) {
  445.             if ((unit = map->selections[i]) != NULL) {
  446.                 fire_the_selected_unit(map, unit, h, v);
  447.             }
  448.         }
  449.     } else if (mods & shiftKey) {
  450.         nearest_unit(map, h, v, &unit);
  451.         if (unit && side_sees_unit(dside, unit)) {
  452.             /* Invert the selection status of the unit. */
  453.             if (unit_is_selected(map, unit)) {
  454.                 unselect_unit_on_map(map, unit);
  455.                 erase_selection(map, unit);
  456.             } else {
  457.                 select_unit_on_map(map, unit);
  458.                 draw_selections_at(map, unit->x, unit->y);
  459.             }
  460.         } else {
  461.             select_all_dragged_over(map, h, v, mods);
  462.         }
  463.     } else {
  464.         /* Interpret an unmodified mouse down. */
  465. #ifdef DESIGNERS
  466.         if (dside->designer && tooltype != notool) {
  467.             apply_designer_tool(map, h, v, mods);
  468.         } else
  469. #endif /* DESIGNERS */
  470.         if (map->moveonclick && !dside->designer) {
  471.             /* Usually will only be one to move, but be general anyway. */
  472.             for (i = 0; i < map->numselections; ++i) {
  473.                 if ((unit = map->selections[i]) != NULL) {
  474.                     move_the_selected_unit(map, unit, h, v);
  475.                 }
  476.             }
  477.         } else {
  478.             unselect_all(map);
  479.             nearest_unit(map, h, v, &unit);
  480.             if (unit != NULL && side_controls_unit(dside, unit)) {
  481.                 select_unit_on_map(map, unit);
  482.                 draw_selections(map);
  483.                 move_on_drag(map, unit, mods);
  484.             } else {
  485.                 select_all_dragged_over(map, h, v, mods);
  486.             }
  487.         }
  488.     }
  489. }
  490.  
  491. select_all_dragged_over(map, h0, v0, mods)
  492. Map *map;
  493. int h0, v0, mods;
  494. {
  495.     Point pt0, pt1, newmouse;
  496.     int h1, v1, drawn = FALSE, x, y;
  497.     Rect tmprect;
  498.  
  499.     SetPt(&pt0, h0, v0);
  500.     SetPt(&pt1, h0, v0);
  501.     SetRect(&tmprect, h0, v0, h0, v0);
  502.     /* (should be a generic subr?) */
  503.     PenMode(patXor);
  504.     PenPat(qd.gray);
  505.     while (WaitMouseUp()) {
  506.         GetMouse(&newmouse);
  507.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  508.             if (drawn) {
  509.                 tmprect.left = min(pt0.h, pt1.h);  tmprect.top = min(pt0.v, pt1.v);
  510.                 tmprect.right = max(pt0.h, pt1.h);  tmprect.bottom = max(pt0.v, pt1.v);
  511.                 FrameRect(&tmprect);
  512.             }
  513.             pt1 = newmouse;
  514.             tmprect.left = min(pt0.h, pt1.h);  tmprect.top = min(pt0.v, pt1.v);
  515.             tmprect.right = max(pt0.h, pt1.h);  tmprect.bottom = max(pt0.v, pt1.v);
  516.             FrameRect(&tmprect);
  517.             drawn = TRUE;
  518.         }
  519.     }
  520.     if (drawn) {
  521.         tmprect.left = min(pt0.h, pt1.h);  tmprect.top = min(pt0.v, pt1.v);
  522.         tmprect.right = max(pt0.h, pt1.h);  tmprect.bottom = max(pt0.v, pt1.v);
  523.         FrameRect(&tmprect);
  524.     }
  525.     PenNormal();
  526.     select_all_units_in_rect(map, &tmprect);
  527. }
  528.  
  529. select_area_and_zoom(map, h0, v0, mods)
  530. Map *map;
  531. int h0, v0, mods;
  532. {
  533.     Point pt0, pt1, newmouse;
  534.     int drawn = FALSE, x, y;
  535.     Rect tmprect;
  536.  
  537.     SetPt(&pt0, h0, v0);
  538.     SetPt(&pt1, h0, v0);
  539.     /* (should be a generic subr) */
  540.     PenMode(patXor);
  541.     PenPat(qd.gray);
  542.     while (WaitMouseUp()) {
  543.         GetMouse(&newmouse);
  544.         if (!EqualPt(pt1, newmouse) /* && PtInRect(newmouse, &(map->window->portRect)) */) {
  545.             if (drawn) {
  546.                 tmprect.left = min(pt0.h, pt1.h);  tmprect.top = min(pt0.v, pt1.v);
  547.                 tmprect.right = max(pt0.h, pt1.h);  tmprect.bottom = max(pt0.v, pt1.v);
  548.                 FrameRect(&tmprect);
  549.             }
  550.             pt1 = newmouse;
  551.             tmprect.left = min(pt0.h, pt1.h);  tmprect.top = min(pt0.v, pt1.v);
  552.             tmprect.right = max(pt0.h, pt1.h);  tmprect.bottom = max(pt0.v, pt1.v);
  553.             FrameRect(&tmprect);
  554.             drawn = TRUE;
  555.         }
  556.     }
  557.     if (drawn) {
  558.         tmprect.left = min(pt0.h, pt1.h);  tmprect.top = min(pt0.v, pt1.v);
  559.         tmprect.right = max(pt0.h, pt1.h);  tmprect.bottom = max(pt0.v, pt1.v);
  560.         FrameRect(&tmprect);
  561.     }
  562.     PenNormal();
  563.     /* Done being modal. */
  564.     modaltool = 0;
  565.     nearest_cell(map, pt1.h, pt1.v, &x, &y);
  566.     if (x != downx && y != downy) {
  567.         magnify_to_fit(map, downx, downy, x, y);
  568.     }
  569. }
  570.  
  571. move_on_drag(map, unit, mods)
  572. Map *map;
  573. Unit *unit;
  574. int mods;
  575. {
  576.     int sx, sy, sw, sh, h0, v0, drawn = FALSE, x, y;
  577.     Point pt0, pt1, newmouse;
  578.  
  579.     xform_unit_self(map, unit, &sx, &sy, &sw, &sh);
  580.     h0 = sx + sw / 2;  v0 = sy + sh / 2;
  581.     SetPt(&pt0, h0, v0);
  582.     SetPt(&pt1, h0, v0);
  583.     /* (should be a generic subr?) */
  584.     PenMode(patXor);
  585.     while (WaitMouseUp()) {
  586.         GetMouse(&newmouse);
  587.         /* should scroll, then abort if we drag outside the window */
  588.         if (0 /* PtInRect(newmouse, &(map->window->portRect)) */) {
  589.         }
  590.         if (!EqualPt(pt1, newmouse)) {
  591.             if (drawn) {
  592.                 MoveTo(h0, v0);  LineTo(pt1.h, pt1.v);
  593.             }
  594.             pt1 = newmouse;
  595.             MoveTo(h0, v0);  LineTo(pt1.h, pt1.v);
  596.             drawn = TRUE;
  597.         }
  598.     }
  599.     /* Erase the last drawn line. */
  600.     if (drawn) {
  601.         MoveTo(h0, v0);  LineTo(pt1.h, pt1.v);
  602.     }
  603.     PenNormal();
  604.     nearest_cell(map, pt1.h, pt1.v, &x, &y);
  605.     if (x != downx || y != downy) {
  606.         move_the_selected_unit(map, unit, pt1.h, pt1.v);
  607.     } else {
  608.         /* (should try to enter another unit in this cell) */
  609.     }
  610. }
  611.  
  612. unselect_all(map)
  613. Map *map;
  614. {
  615.     int num = map->numselections;
  616.  
  617.     if (map->numselections > 0) {
  618.         erase_selections(map);
  619.         map->numselections = 0;
  620.     }
  621. }
  622.  
  623. /* Add the given unit to the array of units selected in the given map.  If we need
  624.    more space, then grow the array by 50%. */
  625.  
  626. select_unit_on_map(map, unit)
  627. Map *map;
  628. Unit *unit;
  629. {
  630.     if (map->numselections >= map->maxselections) {
  631.         int newsize = map->maxselections + map->maxselections / 2;
  632.         Unit **newarray = (Unit **) realloc(map->selections, newsize * sizeof(Unit *));
  633.  
  634.         if (newarray == NULL) {
  635.             run_warning("couldn't realloc map selection array");
  636.             return;
  637.         }
  638.         map->maxselections = newsize;
  639.         map->selections = newarray;
  640.     }
  641.     map->selections[map->numselections++] = unit;
  642. }
  643.  
  644. unit_is_selected(map, unit)
  645. Map *map;
  646. Unit *unit;
  647. {
  648.     int i;
  649.  
  650.     for (i = 0; i < map->numselections; ++i) {
  651.         if (map->selections[i] == unit) return TRUE;
  652.     }
  653.     return FALSE;
  654. }
  655.  
  656. unselect_unit_on_map(map, unit)
  657. Map *map;
  658. Unit *unit;
  659. {
  660.     int i, j;
  661.  
  662.     for (i = 0; i < map->numselections; ++i) {
  663.         if (map->selections[i] == unit) {
  664.             /* Keep selection list contiguous, move other units down. */
  665.             for (j = i + 1; j < map->numselections; ++j) {
  666.                 map->selections[j - 1] = map->selections[j];
  667.             }
  668.             --map->numselections;
  669.             return;
  670.         }
  671.     }
  672. }
  673.  
  674. erase_map_selection(map)
  675. Map *map;
  676. {
  677. }
  678.  
  679. /* Given a map and a rectangle in it, select all the units whose images touch on
  680.    that rectangle. */
  681.  
  682. select_all_units_in_rect(map, rectptr)
  683. Map *map;
  684. Rect *rectptr;
  685. {
  686.     int rectissmall = FALSE;
  687.     int sx, sy, sw, sh;
  688.     Side *side;
  689.     Unit *unit;
  690.     Rect unitrect, tmprect;
  691.     
  692.     /* First see if we're selecting over a large area or within a single cell. */
  693.     if (rectptr->right - rectptr->left < map->hw
  694.         && rectptr->bottom - rectptr->top < map->hh) rectissmall = TRUE;
  695.     /* Now look at all the plausible units and see if any's image intersects the rect. */
  696.     for_all_units(side, unit) {
  697.         if (in_play(unit)
  698.             && side_controls_unit(dside, unit)
  699.             && (rectissmall || unit->transport == NULL)) {
  700.             xform_unit_self(map, unit, &sx, &sy, &sw, &sh);
  701.             SetRect(&unitrect, sx, sy, sx + sw, sy + sh);
  702.             if (SectRect(&unitrect, rectptr, &tmprect)) {
  703.                 select_unit_on_map(map, unit);
  704.                 /* (could do setport etc once...) */
  705.                 draw_selected_unit_setport(map, unit);
  706.             }
  707.         }
  708.     }
  709. }
  710.  
  711. /* This translates the user's "go to here" into appropriate tasks and/or actions. */
  712.  
  713. move_the_selected_unit(map, unit, h, v)
  714. Map *map;
  715. Unit *unit;
  716. int h, v;
  717. {
  718.     int x, y;
  719.     Unit *other;
  720.  
  721.     nearest_cell(map, h, v, &x, &y);
  722. #ifdef DESIGNERS
  723.     /* Designers use this function to push units around, bound only by the
  724.        limits on occupancy. */
  725.     if (dside->designer) {
  726.         nearest_unit(map, h, v, &other);
  727.         if (other != NULL && can_occupy(unit, other)) {
  728.             /* Teleport into a transport. */
  729.             leave_hex(unit);
  730.             enter_transport(unit, other);
  731.         } else if (can_occupy_cell(unit, x, y)) {
  732.             /* Teleport the unit into the designated cell. */
  733.             leave_hex(unit);
  734.             enter_hex(unit, x, y);
  735.         } else {
  736.             SysBeep(20);
  737.         }
  738.         return;
  739.     }
  740. #endif /* DESIGNERS */
  741.     if (x != unit->x || y != unit->y) {
  742.         if (unit->act && unit->plan) { /* (should be more sophisticated test?) */
  743.             if (distance(unit->x, unit->y, x, y) == 1) {
  744.                 if (unit_at(x, y) != NULL) {
  745.                     /* There are units at our desired destination. */
  746.                     nearest_unit(map, h, v, &other);
  747.                     if (other == NULL) {
  748.                         if (can_occupy_cell(unit, x, y)
  749.                             && valid(check_move_action(unit, unit, x, y, unit->z))) {
  750.                             prep_move_action(unit, unit, x, y, unit->z);
  751.                         } else {
  752.                             SysBeep(20);
  753.                         }
  754.                     }
  755.                     if (other->side == unit->side /* (should be "trusted side") */) {
  756.                         /* One of ours, maybe get on it. */
  757.                         if (can_occupy(unit, other)) {
  758.                             if (valid(check_enter_action(unit, unit, other))) {
  759.                                 prep_enter_action(unit, unit, other);
  760.                             } else {
  761.                                 /* (should schedule for next turn?) */
  762.                             }
  763.                         } else if (can_occupy(other, unit)) {
  764.                             /* Have other unit do an enter action, then move. */
  765.                             /* (not quite right, move should happen after other unit
  766.                                 is actually inside, in case it fills dest) */
  767.                             prep_enter_action(other, other, unit);
  768.                             order_moveto(unit, x, y);
  769.                         } else if (other->transport != NULL
  770.                                    && can_occupy(unit, other->transport)) {
  771.                             if (valid(check_enter_action(unit, unit, other->transport))) {
  772.                                 prep_enter_action(unit, unit, other->transport);
  773.                             } else {
  774.                                 /* (should schedule for next turn?) */
  775.                             }
  776.                         } else if (other->transport != NULL
  777.                                    && other->transport->transport != NULL
  778.                                    && can_occupy(unit, other->transport->transport)) {
  779.                             /* two levels up should be sufficient */
  780.                             if (valid(check_enter_action(unit, unit, other->transport->transport))) {
  781.                                 prep_enter_action(unit, unit, other->transport->transport);
  782.                             } else {
  783.                                 /* (should schedule for next turn?) */
  784.                             }
  785.                         } else if (can_occupy_cell(unit, x, y)
  786.                             && valid(check_move_action(unit, unit, x, y, unit->z))) {
  787.                             prep_move_action(unit, unit, x, y, unit->z);
  788.                         } else {
  789.                             SysBeep(20);
  790.                         }
  791.                     } else {
  792.                         /* Somebody else's unit, try to victimize it in various ways,
  793.                            trying coexistence only as a last resort :-) */
  794.                         if (valid(check_capture_action(unit, unit, other))) {
  795.                             prep_capture_action(unit, unit, other);
  796.                         } else if (valid(check_attack_action(unit, unit, other, 100))) {
  797.                             prep_attack_action(unit, unit, other, 100);
  798.                         } else if (valid(check_overrun_action(unit, unit, x, y, unit->z, 100))) {
  799.                             prep_overrun_action(unit, unit, x, y, unit->z, 100);
  800.                         } else if (valid(check_fire_at_action(unit, unit, other, -1))) {
  801.                             prep_fire_at_action(unit, unit, other, -1);
  802.                         } else if (valid(check_detonate_action(unit, unit, x, y, unit->z))) {
  803.                             prep_detonate_action(unit, unit, x, y, unit->z);
  804.                         } else if (valid(check_move_action(unit, unit, x, y, unit->z))) {
  805.                             prep_move_action(unit, unit, x, y, unit->z);
  806.                         } else {
  807.                             SysBeep(20);
  808.                         }
  809.                     }
  810.                 } else {
  811.                     /* Cell is empty, try to move into it directly. */
  812.                     if (can_occupy_cell(unit, x, y)
  813.                         && valid(check_move_action(unit, unit, x, y, unit->z))) {
  814.                         prep_move_action(unit, unit, x, y, unit->z);
  815.                     } else {
  816.                         SysBeep(20);
  817.                     }
  818.                 }
  819.             } else {
  820.                 /* We're not adjacent to the destination, set up a move task. */
  821.                 DGprintf("Ordering %s to move to %d,%d\n", unit_desig(unit), x, y);
  822.                 order_moveto(unit, x, y);
  823.             }
  824.         } else {
  825.             /* ??? can't act ??? */
  826.         }
  827.     } else {
  828.         /* Destination is in this cell, try to do an enter action. */
  829.         nearest_unit(map, h, v, &other);
  830.         if (other != NULL) {
  831.             if (valid(check_enter_action(unit, unit, other))) {
  832.                 prep_enter_action(unit, unit, other);
  833.             } else {
  834.                 SysBeep(20);
  835.             }
  836.         } else {
  837.             /* This is a no-op, don't say anything. */
  838.         }
  839.     }
  840. }
  841.  
  842. fire_the_selected_unit(map, unit, h, v)
  843. Map *map;
  844. Unit *unit;
  845. int h, v;
  846. {
  847.     int x, y;
  848.     Unit *other;
  849.  
  850.     nearest_cell(map, h, v, &x, &y);
  851.     if (x != unit->x || y != unit->y) {
  852.         if (unit->act && unit->plan) { /* (should be more sophisticated test?) */
  853.             if ((other = unit_at(x, y)) != NULL) {
  854.                 /* There's a unit to fire at. */
  855.                 if (other->side == unit->side) {
  856.                     SysBeep(20);
  857.                 } else {
  858.                     prep_fire_at_action(unit, unit, other, -1);
  859.                 }
  860.             } else {
  861.                 SysBeep(20);
  862.             }
  863.         }
  864.     }
  865. }
  866.  
  867. select_exactly_one_unit(map, unit)
  868. Map *map;
  869. Unit *unit;
  870. {
  871.     Unit *thisunit;
  872.  
  873.     if (map->numselections > 0) {        
  874.         thisunit = map->selections[0];
  875.         if (thisunit == unit) return;
  876.     }
  877.     unselect_all(map);
  878.     select_unit_on_map(map, unit);
  879.     scroll_to_unit(map, unit);
  880.     draw_selections(map);
  881. }
  882.  
  883. select_next_unit(map)
  884. Map *map;
  885. {
  886.     select_another(map, find_next_unit);
  887. }
  888.  
  889. select_previous_unit(map)
  890. Map *map;
  891. {
  892.     select_another(map, find_prev_unit);
  893. }
  894.  
  895. select_next_actor(map)
  896. Map *map;
  897. {
  898.     select_another(map, find_next_actor);
  899. }
  900.  
  901. select_previous_actor(map)
  902. Map *map;
  903. {
  904.     select_another(map, find_prev_actor);
  905. }
  906.  
  907. Unit *
  908. find_next_mover(side, prevunit)
  909. Side *side;
  910. Unit *prevunit;
  911. {
  912.     Unit *unit = NULL;
  913.  
  914.     if (side != NULL) {
  915.         if (prevunit == NULL) prevunit = side->unithead;
  916.         for (unit = prevunit->next; unit != prevunit; unit = unit->next) {
  917.             if (is_unit(unit) && unit->id > 0
  918.                 && alive(unit)
  919.                 && inside_area(unit->x, unit->y)
  920.                 && (unit->act && unit->act->acp > 0)) {
  921.                 return unit;
  922.             }
  923.         } 
  924.     }
  925.     return NULL;
  926. }
  927.  
  928. Unit *
  929. find_prev_mover(side, nextunit)
  930. Side *side;
  931. Unit *nextunit;
  932. {
  933.     Unit *unit = NULL;
  934.  
  935.     if (side != NULL) {
  936.     if (nextunit == NULL) nextunit = side->unithead;
  937.     for (unit = nextunit->prev; unit != nextunit; unit = unit->prev) {
  938.         if (is_unit(unit) && unit->id > 0
  939.         && alive(unit)
  940.         && inside_area(unit->x, unit->y)
  941.         && (unit->act && unit->act->acp > 0)) {
  942.         return unit;
  943.         }
  944.     } 
  945.     }
  946.     return NULL;
  947. }
  948.  
  949. select_next_mover(map)
  950. Map *map;
  951. {
  952.     select_another(map, find_next_mover);
  953. }
  954.  
  955. select_previous_mover(map)
  956. Map *map;
  957. {
  958.     select_another(map, find_prev_mover);
  959. }
  960.  
  961. Unit *
  962. find_next_awake_mover(side, prevunit)
  963. Side *side;
  964. Unit *prevunit;
  965. {
  966.     Unit *unit = NULL;
  967.  
  968.     if (side != NULL) {
  969.         if (prevunit == NULL) prevunit = side->unithead;
  970.         for (unit = prevunit->next; unit != prevunit; unit = unit->next) {
  971.             if (is_unit(unit) && unit->id > 0
  972.                 && alive(unit)
  973.                 && inside_area(unit->x, unit->y)
  974.                 && (unit->act && unit->act->acp > 0)
  975.                 && (unit->plan && !unit->plan->asleep && !unit->plan->reserve)) {
  976.                 return unit;
  977.             }
  978.         } 
  979.     }
  980.     return NULL;
  981. }
  982.  
  983. Unit *
  984. find_prev_awake_mover(side, nextunit)
  985. Side *side;
  986. Unit *nextunit;
  987. {
  988.     Unit *unit = NULL;
  989.  
  990.     if (side != NULL) {
  991.     if (nextunit == NULL) nextunit = side->unithead;
  992.     for (unit = nextunit->prev; unit != nextunit; unit = unit->prev) {
  993.         if (is_unit(unit) && unit->id > 0
  994.         && alive(unit)
  995.         && inside_area(unit->x, unit->y)
  996.                 && (unit->act && unit->act->acp > 0)
  997.                 && (unit->plan && !unit->plan->asleep && !unit->plan->reserve)) {
  998.         return unit;
  999.         }
  1000.     } 
  1001.     }
  1002.     return NULL;
  1003. }
  1004.  
  1005. select_next_awake_mover(map)
  1006. Map *map;
  1007. {
  1008.     select_another(map, find_next_awake_mover);
  1009. }
  1010.  
  1011. select_previous_awake_mover(map)
  1012. Map *map;
  1013. {
  1014.     select_another(map, find_prev_awake_mover);
  1015. }
  1016.  
  1017. /* Given a map and a searching function, go find the "next" matching unit and select it. */
  1018.  
  1019. select_another(map, fn)
  1020. Map *map;
  1021. Unit *(*fn)();
  1022. {
  1023.     Unit *thisunit, *nextunit;
  1024.  
  1025.     if (fn == NULL) {
  1026.         SysBeep(20);
  1027.         return;
  1028.     }
  1029.     if (map->numselections > 0) {
  1030.         thisunit = map->selections[0];
  1031.     } else {
  1032.         thisunit = NULL;
  1033.     }
  1034.     nextunit = (*fn)(dside, thisunit);
  1035.     if (nextunit != NULL) {
  1036.         unselect_all(map);
  1037.         select_unit_on_map(map, nextunit);
  1038.         scroll_to_unit(map, nextunit);
  1039.         draw_selections(map);
  1040.         if (map->autoselect) {
  1041.             map->curunit = nextunit;
  1042.         }
  1043.     } else if (thisunit != NULL) {
  1044.         scroll_to_unit(map, thisunit);
  1045.         /* (should not be done this way, but how else?) */
  1046.         if (map->autoselect
  1047.             && (thisunit->act && thisunit->act->acp > 0)
  1048.             && (thisunit->plan && !thisunit->plan->asleep && !thisunit->plan->reserve)) {
  1049.             map->curunit = thisunit;
  1050.         }
  1051.     }
  1052. }
  1053.  
  1054. /* Scroll the given map over to display the given unit. */
  1055.  
  1056. scroll_to_unit(map, unit)
  1057. Map *map;
  1058. Unit *unit;
  1059. {
  1060.     if (inside_area(unit->x, unit->y)) {
  1061.         if (!in_middle(map, unit->x, unit->y)) {
  1062.             map->vcx = unit->x;  map->vcy = unit->y;
  1063.             center_on_focus(map);
  1064.             set_map_scrollbars(map);
  1065.             force_map_update(map);
  1066.         }
  1067.     }
  1068. }
  1069.  
  1070. /* This routine changes a map's viewport and magnification to fit the given rectangle. */
  1071.  
  1072. magnify_to_fit(map, x1, y1, x2, y2)
  1073. Map *map;
  1074. int x1, y1, x2, y2;
  1075. {
  1076.     int wid, hgt, wanted, power;
  1077.  
  1078.     DGprintf("Magnifying map to fit in area %d,%d - %d,%d\n", x1, y1, x2, y2);
  1079.     /* (still need to do y/2 correction) */
  1080.     wid = abs(x2 - x1) + 1;  hgt = abs(y2 - y1) + 1;
  1081.     map->vcx = min(x1, x2) + wid / 2;  map->vcy = min(y1, y2) + hgt / 2;
  1082.     /* Compute the "ideal" size of a displayed cell. */
  1083.     wanted = min(map->pxw / wid, map->pxh / hgt);
  1084.     /* Search for the best approximation. */
  1085.     for (power = NUMPOWERS-1; power > 0; --power) {
  1086.         if (hws[power] < wanted) break;
  1087.     }
  1088.     set_map_mag(map, power);
  1089. }
  1090.